/*
 * aes_cipher_stream.h
 *
 *  Created on: Apr 6, 2011
 *      Author: Erich Malzer
 */

#ifndef AESCIPHERSTREAM_H_
#define AESCIPHERSTREAM_H_

#include "crypto/cipher_stream.h"

#include <cryptopp/osrng.h>
using CryptoPP::AutoSeededRandomPool;

#include <ios>
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;

#include <string>
using std::string;

#include <cstdlib>
using std::exit;

#include <cryptopp/cryptlib.h>
using CryptoPP::Exception;

#include <cryptopp/hex.h>
using CryptoPP::HexEncoder;
using CryptoPP::HexDecoder;

#include <cryptopp/filters.h>
using CryptoPP::StringSink;
using CryptoPP::StringSource;
using CryptoPP::StreamTransformationFilter;

#include <cryptopp/aes.h>
using CryptoPP::AES;

#include <cryptopp/modes.h>
using CryptoPP::OFB_Mode;

#include <cryptopp/sha.h>
using CryptoPP::SHA256;

class CAESCipherStream : public CCipherStream
{
public:
	/**
	 * Constructor of CAESCipherStream class. Takes the password as a parameter and
	 * initializes the AES cipher stream. The AES cipher stream is initialized in OFB
	 * mode.
	 *
	 * @param pPassword    The password that serves as the key and the initialization
	 *                     vector of the AES cipher stream (in other words: the same
	 *                     password gives the same cipher stream).
	 */
	CAESCipherStream(std::string *pPassword);

	/*
	 * The destructor of CAESCipherStream class.
	 */
	virtual ~CAESCipherStream();

	/**
	 * Gets the next pCount bytes of the AES cipher stream and writes them onto the
	 * pStream string. It automatically takes a char array with a length of pCount and
	 * fills it with zero bytes. This char array is taken as the plain text so that we
	 * get a pure cipher stream which only depends on the password (which is also taken
	 * as the IV).
	 *
	 * @param pStream    The std::string where the cipher stream bytes are written on
	 *                   (don't forget to specify the correct length with pCount)
	 * @param pCount     The length of the pStream string and therefore the amount of
	 *                   bytes of the cipher stream that should be returned
	 */
	virtual void getNext(std::string *pStream, unsigned int pCount);

	/**
	 * Returns a fixed part of the cipher stream without taking into account the
	 * current position in the stream. With this method, any part of the stream can be
	 * read as often as desired.
	 *
	 * @param pStream    The std::string where the cipher stream bytes are written on
	 * @param pCount     The length of the pStream string and therefore the amount of
	 *                   bytes of the cipher stream that should be returned
	 * @param pOffset    The offset inside the AES cipher stream
	 */
	virtual bool getStaticKey(std::string*, unsigned int pCount, unsigned int pOffset);

	/**
	 * Resets the AES cipher stream with the given password. It basically does the same
	 * as creating a new object of this class. The password is taken as the key and the
	 * initialization vector of the AES cipher stream (which is initialized in OFB
	 * mode).
	 *
	 * @param pPassword    The password that serves as the key and the initialization
	 *                     vector of the AES cipher stream (in other words: the same
	 *                     password gives the same cipher stream).
	 */
	virtual void reset(std::string *pPassword);

	/**
	 * Encodes a given byte stream in hex. This method may be used for debugging
	 * purposes, such as logging or displaying the password hash in the command line.
	 *
	 * @param pData    The data to be hex-encoded
	 * @param pSize    The size of the data array
	 */
	static std::string hexEncode(byte *pData, int pSize);

private:
	/* The AES encryption object from cryptopp library */
	OFB_Mode<AES>::Encryption *mAES;
	std::string mStaticCipherStream;
};

#endif /* AESCIPHERSTREAM_H_ */
